package com.codebo.homiematchbackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codebo.homiematchbackend.common.ErrorCode;
import com.codebo.homiematchbackend.constant.UserConstant;
import com.codebo.homiematchbackend.exception.BusinessException;
import com.codebo.homiematchbackend.exception.ThrowUtils;
import com.codebo.homiematchbackend.mapper.UserMapper;
import com.codebo.homiematchbackend.model.dto.user.FollowUserRequest;
import com.codebo.homiematchbackend.model.dto.user.RegisterRequest;
import com.codebo.homiematchbackend.model.dto.user.UserQueryRequest;
import com.codebo.homiematchbackend.model.entity.Follow;
import com.codebo.homiematchbackend.model.entity.User;
import com.codebo.homiematchbackend.model.vo.UserVO;
import com.codebo.homiematchbackend.service.BlogService;
import com.codebo.homiematchbackend.service.FollowService;
import com.codebo.homiematchbackend.service.UserService;
import com.codebo.homiematchbackend.utils.SelfUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author 25912
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2025-09-13 14:46:21
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService
{

    @Resource
    private SelfUtil selfUtil;

    @Resource
    private FollowService followService;


    @Override
    public UserVO login(String userAccount, String userPassword, HttpServletRequest httpServletRequest)
    {
        //验证参数
        ThrowUtils.throwIf(StrUtil.hasBlank(userAccount, userPassword), ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(userAccount.length() < 3, ErrorCode.PARAMS_ERROR, "账号长度太短");
        ThrowUtils.throwIf(userPassword.length() < 3, ErrorCode.PARAMS_ERROR, "密码长度太短");

        //构建查询条件
        QueryWrapper qw = new QueryWrapper();
        qw.eq("user_account", userAccount);
        qw.eq("user_password", userPassword);
        User user = baseMapper.selectOne(qw);

        //验证用户
        ThrowUtils.throwIf(user == null, ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        ThrowUtils.throwIf(user.getStatus() == 0, ErrorCode.NO_AUTH_ERROR, "用户被禁用");

        //将用户信息存入session
        httpServletRequest.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);
        return getUserVO(user);
    }

    @Override
    public Long register(RegisterRequest registerRequest)
    {
        String userAccount = registerRequest.getUserAccount();
        String userPassword = registerRequest.getUserPassword();
        String checkPassword = registerRequest.getCheckPassword();
        String username = registerRequest.getUsername();
        List<String> userTags = registerRequest.getUserTags();
        List<String> teach = registerRequest.getTeach();
        List<String> learn = registerRequest.getLearn();

        //验证参数
        ThrowUtils.throwIf(StrUtil.hasBlank(userAccount, userPassword), ErrorCode.PARAMS_ERROR, "参数不能为空");
        ThrowUtils.throwIf(userAccount.length() < 3, ErrorCode.PARAMS_ERROR, "账号长度太短");
        ThrowUtils.throwIf(!userPassword.equals(checkPassword), ErrorCode.PARAMS_ERROR, "密码不一致");
        ThrowUtils.throwIf(userPassword.length() < 3, ErrorCode.PARAMS_ERROR, "密码长度太短");

        //构建查询条件
        QueryWrapper qw = new QueryWrapper();
        qw.eq("user_account", userAccount);
        User user = baseMapper.selectOne(qw);

        //验证用户
        ThrowUtils.throwIf(user != null, ErrorCode.PARAMS_ERROR, "账号已存在");

        //插入数据库
        user = new User();
        BeanUtil.copyProperties(registerRequest, user);
        user.setUserTags(JSONUtil.toJsonStr(userTags));
        user.setUsername(StrUtil.hasBlank(username) ? "无名" : username);
        user.setTeach(JSONUtil.toJsonStr(teach));
        user.setLearn(JSONUtil.toJsonStr(learn));

        boolean save = save(user);
        if (!save)
        {
            log.error("数据库错误，用户注册时出错");
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败");
        }
        return user.getId();
    }

    @Override
    @Transactional
    public boolean followUser(FollowUserRequest followUserRequest)
    {
        Long userId = followUserRequest.getUserId();
        Long followedId = followUserRequest.getFollowedId();
        Boolean isFollow = followUserRequest.getIsFollow();
        ThrowUtils.throwIf(userId == null || userId <= 0, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(followedId == null || followedId <= 0, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(userId.equals(followedId), ErrorCode.PARAMS_ERROR, "不能关注自己");
        User user = this.getById(userId);
        User followedUser = this.getById(followedId);
        ThrowUtils.throwIf(user == null || followedUser == null, ErrorCode.NOT_FOUND_ERROR, "请求用户不存在");
        //操作数据库
        Follow follow = new Follow();
        BeanUtil.copyProperties(followUserRequest, follow);
        boolean followSave = false;
        boolean updateUser = false;
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        QueryWrapper<Follow> queryWrapper = new QueryWrapper<>();
        Follow getOne = followService.getOne(queryWrapper.eq("user_id", userId).eq("followed_id", followedId));
        if (!isFollow)
        {
            ThrowUtils.throwIf(getOne != null, ErrorCode.PARAMS_ERROR, "已关注");
            //操作follow表
            followSave = followService.save(follow);
            //关注数、粉丝数变化
            updateWrapper.eq("id", userId)
                    .setSql("follow_count = follow_count + 1");
            this.update(updateWrapper);
            updateWrapper.clear();
            updateWrapper.eq("id", followedId)
                    .setSql("fan_count = fan_count + 1");
        } else
        {
            ThrowUtils.throwIf(getOne == null, ErrorCode.PARAMS_ERROR, "未关注");
            //操作follow表
            queryWrapper.eq("user_id", userId)
                    .eq("followed_id", followedId);
            followSave = followService.removeById(getOne);
            //关注数、粉丝数变化
            updateWrapper.eq("id", userId)
                    .setSql("follow_count = follow_count - 1");
            this.update(updateWrapper);
            updateWrapper.clear();
            updateWrapper.eq("id", followedId)
                    .setSql("fan_count = fan_count - 1");
        }
        updateUser = this.update(updateWrapper);
        ThrowUtils.throwIf(!(followSave && updateUser), ErrorCode.OPERATION_ERROR, "操作失败");
        return true;
    }

    @Override
    public boolean logout(HttpServletRequest httpServletRequest)
    {
        //判断是否已登录
        ThrowUtils.throwIf(httpServletRequest.getSession().getAttribute(UserConstant.USER_LOGIN_STATE) == null, ErrorCode.NOT_LOGIN_ERROR);
        //退出登录
        httpServletRequest.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
        return true;
    }

    //    @Override
//    public Page<UserVO> listUserByRecommend(Page<User> userPage,HttpServletRequest httpServletRequest)
//    {
//        //查出所有用户-编辑距离-得到排序-分页-返回page
//        // 1. 当前登录用户
//        User loginUser = getLoginUser(httpServletRequest);
//        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
//        // 2. 全量用户
//        List<User> allUsers = userPage.getRecords();
//
//        // 3. 并行计算：User -> 加权距离
//        Map<User, Integer> distanceMap = new ConcurrentHashMap<>(allUsers.size());
//        allUsers.parallelStream().forEach(u -> {
//            int d = 0;
//            d += 1 * selfUtil.editDistance(loginUser.getUserProfile(),  u.getUserProfile());
//            d += 3 * selfUtil.editDistance(loginUser.getUserTags(),      u.getUserTags());
//            d += 4 * selfUtil.editDistance(loginUser.getTeach(),         u.getTeach());
//            d += 4 * selfUtil.editDistance(loginUser.getLearn(),         u.getLearn());
//            distanceMap.put(u, d);
//        });
//
//        // 4. 排序（距离越小越相似）
//        List<User> sorted = allUsers.stream()
//                .sorted(Comparator.comparingInt(distanceMap::get))
//                .collect(Collectors.toList());
//
//        // 5. 手动分页
//        long current = userPage.getCurrent();
//        long size    = userPage.getSize();
//        long total   = sorted.size();
//        long start   = (current - 1) * size;
//        long end     = Math.min(start + size, total);
//        List<UserVO> voList = sorted.subList((int) start, (int) end)
//                .stream()
//                .map(this::getUserVO)   // 自己写转换
//                .collect(Collectors.toList());
//        Page<UserVO> userVOPage = new Page<>(current, size, total);
//        userVOPage.setRecords(voList);
//        //6.过滤自己
//        userVOPage.getRecords().removeIf(u -> u.getId().equals(loginUser.getId()));
//        userVOPage.setTotal(total - 1);
//
//        return userVOPage;
//
//    }
    @Override
    public List<UserVO> listUserByRecommend(HttpServletRequest request, UserQueryRequest userQueryRequest)
    {
        // 1. 当前登录用户
        User loginUser = getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);

        // 2. 随机 50 条用户（排除自己）
        QueryWrapper<User> queryWrapper = this.getQueryWrapper(userQueryRequest);
        queryWrapper.getExpression().getOrderBy().clear();
        queryWrapper.ne("id", loginUser.getId())//排除自己
                .last("ORDER BY RAND() LIMIT 50");
        List<User> candidates = this.list(queryWrapper);

        if (CollUtil.isEmpty(candidates))
        {
            return Collections.emptyList();
        }

        // 3. 并行计算加权编辑距离
        Map<User, Integer> distanceMap = new ConcurrentHashMap<>(candidates.size());
        candidates.parallelStream().forEach(u ->
        {
            int d = 0;
            d += 1 * selfUtil.editDistance(loginUser.getUserProfile(), u.getUserProfile());
            d += 3 * selfUtil.editDistance(loginUser.getUserTags(), u.getUserTags());
            d += 4 * selfUtil.editDistance(loginUser.getTeach(), u.getTeach());
            d += 4 * selfUtil.editDistance(loginUser.getLearn(), u.getLearn());
            distanceMap.put(u, d);
        });

        // 4. 排序并取前 10
        return candidates.stream()
                .sorted(Comparator.comparingInt(distanceMap::get))
                .limit(9)
                .map(this::getUserVO)
                .collect(Collectors.toList());
    }


    @Override
    public UserVO getUserVO(User user)
    {
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR);
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(user, userVO);
        userVO.setUserTags(JSONUtil.toList(user.getUserTags(), String.class));
        userVO.setTeach(JSONUtil.toList(user.getTeach(), String.class));
        userVO.setLearn(JSONUtil.toList(user.getLearn(), String.class));
        return userVO;
    }

    @Override
    public User getLoginUser(HttpServletRequest httpServletRequest)
    {
        Object object = httpServletRequest.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        ThrowUtils.throwIf(object == null, ErrorCode.NOT_LOGIN_ERROR);
        return (User) object;
    }

    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest)
    {
        ThrowUtils.throwIf(userQueryRequest == null, ErrorCode.PARAMS_ERROR);
        Long id = userQueryRequest.getId();
        String userAccount = userQueryRequest.getUserAccount();
        String username = userQueryRequest.getUsername();
        String userProfile = userQueryRequest.getUserProfile();
        String searchText = userQueryRequest.getSearchText();
        List<String> userTags = userQueryRequest.getUserTags();
        List<String> teach = userQueryRequest.getTeach();
        List<String> learn = userQueryRequest.getLearn();
        String userRole = userQueryRequest.getUserRole();
        Integer status = userQueryRequest.getStatus();
        Integer points = userQueryRequest.getPoints();
        Integer blogCount = userQueryRequest.getBlogCount();
        Long blogTotalView = userQueryRequest.getBlogTotalView();
        Integer likeCount = userQueryRequest.getLikeCount();
        Integer collectCount = userQueryRequest.getCollectCount();
        Integer followCount = userQueryRequest.getFollowCount();
        Integer fanCount = userQueryRequest.getFanCount();
        Date startTime = userQueryRequest.getStartTime();
        Date endTime = userQueryRequest.getEndTime();
        int current = userQueryRequest.getCurrent();
        int pageSize = userQueryRequest.getPageSize();
        String sortField = userQueryRequest.getSortField();
        String sortOrder = userQueryRequest.getSortOrder();


        QueryWrapper<User> qw = new QueryWrapper();
        qw.eq(ObjUtil.isNotEmpty(id), "id", id);
        qw.eq(StrUtil.isNotBlank(userAccount), "user_account", userAccount);
        qw.like(StrUtil.isNotBlank(username), "username", username);
        qw.eq(StrUtil.isNotBlank(userProfile), "user_profile", userProfile);
        if (CollUtil.isNotEmpty(userTags))
        {
            /* and (tag like "%\"Java\"%" and like "%\"Python\"%") */
            for (String tag : userTags)
            {
                qw.like("user_tags", "\"" + tag + "\"");
            }
        }
        if (StrUtil.isNotBlank(searchText))
        {
            qw.and(qw1 -> qw1.like("username", searchText)
                    .or()
                    .like("user_profile", searchText));
        }
        if (CollUtil.isNotEmpty(teach))
        {
            /* and (tag like "%\"Java\"%" and like "%\"Python\"%") */
            for (String t : teach)
            {
                qw.like("teach", "\"" + t + "\"");
            }
        }
        if (CollUtil.isNotEmpty(learn))
        {
            /* and (tag like "%\"Java\"%" and like "%\"Python\"%") */
            for (String l : learn)
            {
                qw.like("learn", "\"" + l + "\"");
            }
        }
        qw.eq(StrUtil.isNotBlank(userRole), "user_role", userRole);
        qw.eq(ObjUtil.isNotEmpty(status), "status", status);
// >= startEditTime
        qw.ge(ObjUtil.isNotEmpty(startTime), "create_time", startTime);
        // < endEditTime
        qw.lt(ObjUtil.isNotEmpty(endTime), "create_time", endTime);
        qw.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);

        return qw;

    }

    @Override
    public List<UserVO> getUserVOList(List<User> users)
    {
        return users.stream().map(this::getUserVO).collect(Collectors.toList());
    }


}




